package com.frxuexi.base.mvi

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.cachedIn
import com.frxuexi.base.entity.Res
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import java.util.Random

abstract class BaseViewModel<UiIntent : IUiIntent> : ViewModel() {
    private val channel = Channel<UiIntent>()

    private var _uiState = MutableStateFlow<UiState>(UiState.onLoading)
    val uiState: StateFlow<UiState>
        get() = _uiState

    init {
        viewModelScope.launch {
            channel.receiveAsFlow().collect {
                handleIntent(it)
            }
        }
    }

    abstract fun handleIntent(it: UiIntent)

    fun sendIntent(intent: UiIntent) {
        viewModelScope.launch {
            channel.send(intent)
        }
    }

    /**
     * 网络请求
     * request：请求的网络接口
     * type：区别是什么网络请求
     */
    fun <T> httpRequest(request: Flow<Res<T>>, type: RequestType = RequestType.DEFAULT) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.i("lr", it.message.toString())
                }.collect {
                    if (it.code == 200 || it.code == 0) {
                        if(it.data is Boolean){
                            val num = Random().nextInt()
                            _uiState.value = UiState.onSuccess("${it.data}-${num}", type)
                        }else {
                            _uiState.value = UiState.onSuccess(it.data, type)
                        }
                    } else {
                        _uiState.value = UiState.onError(it.message ?: it.msg)
                    }
                }
        }
    }

    /**
     * 网络请求，方便LiveData处理
     * request：请求的网络接口
     */
    fun <T> httpRequestLive(
        request: Flow<Res<T>>,
        res: (T) -> Unit = {},
        error: (String) -> Unit = {}
    ) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.i("lr", it.message.toString())
                }.collect {
                    if (it.code == 200) {
                        res(it.data)
                    } else {
                        error(it.message)
                        Log.i("lr", it.message)
                    }
                }
        }
    }

    fun <T> roomRequest(request: Flow<T>, type: RequestType = RequestType.DEFAULT) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.i("lr", it.message.toString())
                }.collect {
                    if (it != null) {
                        _uiState.value = UiState.onSuccess(it, type)
                    } else {
                        _uiState.value = UiState.onError("数据库操作失败")
                    }
                }
        }
    }

    fun <T : Any> pagerRequest(pagingSource: () -> PagingSource<Int, T>) {
        val pager = Pager(config = PagingConfig(pageSize = 10), pagingSourceFactory = {
            pagingSource()
        }).flow.cachedIn(viewModelScope)

        viewModelScope.launch {
            pager.flowOn(Dispatchers.IO)
                .catch {
                    _uiState.value = UiState.onError(it.message!!)
                }.collect {
                    _uiState.value = UiState.onSuccess(it)
                }
        }
    }

    fun toBody(item: Any): RequestBody {
        val json = Gson().toJson(item)
        return RequestBody.create("application/json".toMediaTypeOrNull(), json)
    }

    fun toMultipartBody(name:String,path:String):MultipartBody{
        val requestBody =
            RequestBody.create("multipart/form-data".toMediaTypeOrNull(), File(path))
        return MultipartBody.Builder().addFormDataPart("file", name, requestBody).build()
    }
}